#ifndef DXDEVICE_H
#define DXDEVICE_H
#include <d3d11_1.h>
#include "Shader.h"
#include "XMath.h"
#include "Texture.h"
#include "RenderTarget.h"
#include "Material.h"
#include "Sampler.h"
#include "XColladaDX.h"
class DXDevice : public Singleton<DXDevice>
{
protected:
	//static DXDevice* instance;
	ID3D11Device1* m_d3dDevice;
	ID3D11DeviceContext1* m_d3dContext;
	RenderTarget* renderTargetMain;
	std::vector<RenderTarget*> renderTargetStack;
	int m_Width, m_Height;
	Matrix  m_MatrixProjection, m_MatrixView, m_MatrixProjection2D, m_MatrixProjectionStore, m_MatrixProjection2DLogical;
	std::vector<Matrix> m_MatrixStack;
	VertexShader* vsActived;
	PixelShader* psActived;
	Material* materialActived;
	ID3D11DepthStencilState * pDepthStencilStateCurrent;
	D3D11_DEPTH_STENCIL_DESC depthStencilDescCurrent;
	ID3D11BlendState1* pBlendStateCurrent;
	D3D11_BLEND_DESC1 blendStateDescCurrent;
	float blendFactor[4];
	unsigned int blendSampleMask;
	bool isDrawing2D;
	ID3D11Buffer* m_vertexBuffer2D;
	ID3D11Query* queryEvent;
	bool bCommandCheckingStarted;
public:
	enum DeviceType
	{
		DEVICE_UNKNOW,
		DEVICE_WP8_XAML,
	};
	ID3D11Device1* GetD3D11Device()
	{
		return m_d3dDevice;
	}
	ID3D11DeviceContext1* GetDeviceContext()
	{
		return m_d3dContext; //GetImmediateContext
	}

	static void Init(void* params[]);
	virtual void UpdateDevice(_In_ ID3D11Device1* device, _In_ ID3D11DeviceContext1* context, _In_ ID3D11RenderTargetView* renderTargetView) //for WP8 XAML
	{
	}
	virtual DeviceType GetDeviceType()
	{
		return DeviceType::DEVICE_UNKNOW;
	}
	virtual void Resume()
	{
	}
	virtual void Suspend()
	{
	}
	static void Release()
	{
		SafeRelease(instance->queryEvent);
		SafeRelease(instance->pDepthStencilStateCurrent);
		SafeRelease(instance->pBlendStateCurrent);
		for(std::vector<RenderTarget*>::iterator it = instance->renderTargetStack.begin(); it != instance->renderTargetStack.end(); ++it)
		{
			SafeDelete(*(it));
		}
		instance->renderTargetStack.clear();
		SafeRelease(instance);
	}
	virtual HRESULT CreateVertexBufferFromVerticesData(float* verticesData, UINT dataLength, ID3D11Buffer** vBufferIdOuput)
	{
		return 0;
	}
	virtual void FlipBuffer()
	{
	}
	virtual int GetWidth()
	{
		return m_Width;
	}
	virtual int GetHeight()
	{
		return m_Height;
	}
	virtual void ClearColorBuffer(float rgba[4])
	{
	}
	virtual void ClearDepthStencilBuffer()
	{
	}
	virtual void CreateVertexShaderFromCompiledResource(char* fileName)
	{
	}
	virtual void SetActiveVertexShader(VertexShader* vs);
	virtual void SetActivePixelShader(PixelShader* ps);
	virtual void SetActiveMaterial(Material* m);
	virtual VertexShader* GetActiveVertexShader()
	{
		return vsActived;
	}
	virtual PixelShader* GetActivePixelShader()
	{
		return psActived;
	}
	virtual Material* GetActiveMaterial()
	{
		return materialActived;
	}
	virtual void PushMatrix();
	virtual void PopMatrix();
	virtual void SetIdentityMatrix();
	void Transform(const Matrix &matrix);
	void TransformLocal(const Matrix &matrix);
	void Translate(float x, float y, float z);
	void Scale(float x, float y, float z);
	void RotateOz(float radian, float x, float y);
	void RotateOz(float radian);
	void RotateOy(float radian);
	void RotateAxis(float radian, float x, float y, float z);
	void SetProjectionPerspectiveMatrix(float angleFovy, float ratio, float fNear, float fFar);
	void SetProjectionOrthoMatrix(float left, float right, float bottom, float top, float zNear, float zFar); //zNear must not equal 0.0f
	void SetProjectionMatrix(Matrix  &matrix);
	void SetViewMatrix(float xEye, float yEye, float zEye, float xDes, float yDes, float zDes, float xUp, float yUp, float zUp);
	void SetViewMatrix(Matrix  &matrix);
	void SetViewport(float x, float y, float width, float height);
	Matrix  GetMatrixProjection()
	{
		return m_MatrixProjection;
	}
	Matrix  GetMatrixView()
	{
		return m_MatrixView;
	}
	Matrix  GetMatrixWorld()
	{
		return m_MatrixStack.back();
	}
	Matrix  GetMatrixWorldViewProjection();
	//virtual bool SetCurrentVertexShaderUniformBufferData(int start, int count, void* data);
	//virtual bool SetCurrentPixelShaderUniformBufferData(int start, int count, void* data);
	void Draw(D3D_PRIMITIVE_TOPOLOGY primitiveType, UINT startIndex, UINT count);
	void BeginDraw2D();
	void EndDraw2D();
	void Draw2DTextureScreenCoord(Texture* texture, Sampler* sampler, RectScreenF des, RectScreenF source);
	void Draw2DTextureLogicalCoord(Texture* texture, Sampler* sampler, RectScreenF des, RectScreenF source); // height: -1.0 -> 1.0
	void Draw2DTextureFullViewport(Texture* texture, Sampler* sampler);
	void DrawXColladaDX(XColladaDX* mesh);
	void SetDepthTest(BOOL enable);
	void SetStencilTest(BOOL enable);
	void SetBlend(BOOL enable);
	RenderTarget* GetCurrentRenderTarget();
	void PushRenderTarget(RenderTarget* rt);
	void PopRenderTarget();
	void StartCommandChecking();
	void StopCommandChecking();
	void FlushCommand();
protected:
	virtual void InitSpecificDevice()
	{
	}
	virtual void InitMatrixStack();
};
#endif